#include "server.h"
#include "http.h"
#define VERBOSE
#define DEBUG

struct SocketState sockets[MAX_SOCKETS] = { 0 };
int socketCount = 0;

void main()
{
	initServer();

	while (1)
	{
#ifdef DEBUG
		printCurrentSockets();
#endif
		fd_set waitRecv;
		fd_set waitSend;
		FD_ZERO(&waitRecv);
		FD_ZERO(&waitSend);

		for(int i = 0 ; i < socketCount ; i++)
		{
			if(sockets[i].send == SEND)
			{
				FD_SET(sockets[i].id, &waitSend);
			}
			else if((sockets[i].recv == LISTEN) || (sockets[i].recv == RECEIVE))
			{
				FD_SET(sockets[i].id, &waitRecv);
			}
		}

		int nfd;
		nfd = select(0, &waitRecv, &waitSend, NULL, NULL);
		if(nfd == SOCKET_ERROR)
		{
			cout << "HTTP Server Error at select." << WSAGetLastError() << endl;
			WSACleanup();
			exit(1);
		}

		for(int i = 0 ; i < socketCount && nfd > 0 ; i++)
		{
			if(FD_ISSET(sockets[i].id, &waitRecv))
			{
				nfd--;
				switch(sockets[i].recv)
				{
				case LISTEN:
					acceptConnection(i);
					break;

				case RECEIVE:
					receiveMessage(i);
					break;
				}
			}
		}

		for(int i = 0 ; i < socketCount && nfd > 0 ; i++)
		{
			if(FD_ISSET(sockets[i].id, &waitSend))
			{
				nfd--;
				sendMessage(i);
			}
		}

		timeOutRemover();
	} 

	cout << "HTTP Server Closing connection" << endl;
	closesocket(sockets[0].id);
	WSACleanup();
}

void initServer()
{
	WSAData wsaData;
	if (NOERROR != WSAStartup(MAKEWORD(2,2), &wsaData))
	{
		cout << "HTTP Server Error at WSAStartup." << endl;
		exit(1);
	}

	SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listenSocket == INVALID_SOCKET)
	{
		cout << "HTTP Server Error at socket." << endl;
		WSACleanup();
		exit(1);
	}

	sockaddr_in serverService;
	serverService.sin_family = AF_INET;
	serverService.sin_addr.s_addr = INADDR_ANY;
	serverService.sin_port = htons(HTTP_PORT);

	if(bind(listenSocket, (SOCKADDR *) &serverService, sizeof(serverService)) == SOCKET_ERROR)
	{
		cout << "HTTP Server Error at bind." << endl;
		closesocket(listenSocket);
		WSACleanup();
		exit(1);
	}

	if(listen(listenSocket, 5) == SOCKET_ERROR)
	{
		cout << "HTTP Server Error at listen." << endl;
		closesocket(listenSocket);
		WSACleanup();
		exit(1);
	}

	cout << "HTTP Server is up!" << endl;
	addSocket(listenSocket, LISTEN);
}

void timeOutRemover()
{
	time_t currentTime = time(NULL);
	struct SocketState socketsToKeep[MAX_SOCKETS];

	time(&currentTime);

	int j = 1;
	for(int i = 1 ; i < socketCount ; i++)
	{
		if(currentTime - sockets[i].lastTransmission > TIMEOUT)
		{
			cout << "HTTP Server: closing connection (timeout): "; printAddressPort(i);	cout << endl;
			closesocket(sockets[i].id);
		}
		else
		{
			socketsToKeep[j] = sockets[i];
			j++;
		}
	}

	socketCount = j;
	for(int i = 1 ; i < socketCount ; i++)
	{
		sockets[i] = socketsToKeep[i];
	}
}

bool addSocket(SOCKET id, int type)
{
	if (socketCount == MAX_SOCKETS)
	{
		return false;
	}

	sockets[socketCount].id = id;
	sockets[socketCount].recv = type;
	sockets[socketCount].send = IDLE;
	sockets[socketCount].len = 0;
	sockets[socketCount].file = NULL;
	time(&sockets[socketCount].lastTransmission);
	socketCount++;

	return true;
}

void removeSocket(int index)
{
	sockets[index] = sockets[socketCount - 1];
	socketCount--;
}

void acceptConnection(int index)
{
	SOCKET id = sockets[index].id;
	struct sockaddr_in from;
	int fromLen = sizeof(from);

	SOCKET msgSocket = accept(id, (struct sockaddr *)&from, &fromLen);

	if (msgSocket == INVALID_SOCKET)
	{
		cout << "Error at accept." << endl;
		cout << "socket id = " << id << endl;
		return;
	}
	cout << "Accepted connection from "; printAddressPort(index); cout << endl;

	unsigned long flag = 1;
	if (ioctlsocket(msgSocket, FIONBIO, &flag) != 0)
	{
		cout << "HTTP Server Error at ioctlsocket(): " << WSAGetLastError() << endl;
	}

	if (!addSocket(msgSocket, RECEIVE))
	{
		cout << "Too many connections, dropped." << endl;
		closesocket(id);
	}
}

void sendMessage(int i_Index)
{
	int bytesSent = 0;
	SOCKET msgSocket = sockets[i_Index].id;
	char* message = NULL;
	int headerLen = strlen(sockets[i_Index].buffer);
	int messageLen = headerLen;

	if (sockets[i_Index].file != NULL)
	{
		messageLen += sockets[i_Index].fileSize;
	}

	message = (char*) malloc(sizeof(char) * messageLen);
	strncpy(message, sockets[i_Index].buffer, messageLen);
	
	if (sockets[i_Index].file != NULL)
	{
		memcpy(message + headerLen, sockets[i_Index].file, sizeof(char) * sockets[i_Index].fileSize);
		free(sockets[i_Index].file);
		sockets[i_Index].file = NULL;
		sockets[i_Index].fileSize = 0; 
	}

	bytesSent = send(msgSocket, message, messageLen, 0);
	if (bytesSent == SOCKET_ERROR)
	{
		cout << "HTTP Server: Error at send(): " << WSAGetLastError() << endl;	
		return;
	}

#ifdef VERBOSE
	cout << "HTTP Server: Sent "; 
	printAddressPort(i_Index); 
	cout << " " << bytesSent << "\\" << messageLen << " bytes of \n ---START---\n" << message << "\n ---END---\n";	
#endif

	free(message);
	sockets[i_Index].len = 0;
	sockets[i_Index].buffer[0] = NULL;
	sockets[i_Index].send = IDLE;
}

void printAddressPort(int i_Index)
{
	struct sockaddr_in hostName;
	int hostLen = sizeof(hostName);

	getpeername(sockets[i_Index].id, (sockaddr *)&hostName, &hostLen);
	cout << inet_ntoa(hostName.sin_addr) << ":" << ntohs(hostName.sin_port);
}

void receiveMessage(int i_Index)
{
	SOCKET msgSocket = sockets[i_Index].id;
	int len = sockets[i_Index].len;
	int bytesRecv = recv(msgSocket, sockets[i_Index].buffer + len, sizeof(sockets[i_Index].buffer) - len, 0);

	time(&sockets[i_Index].lastTransmission);

	if(bytesRecv == SOCKET_ERROR)
	{
		cout << "HTTP Server: Connection lost: "; printAddressPort(i_Index); cout << endl;
		closesocket(msgSocket);
		removeSocket(i_Index);
		return;
	}

	if(bytesRecv == 0)
	{
		cout << "HTTP Server: Closing connection: "; printAddressPort(i_Index); cout << endl;
		closesocket(msgSocket);
		removeSocket(i_Index);
		return;
	}

	else
	{
		sockets[i_Index].buffer[len + bytesRecv] = '\0';
		sockets[i_Index].len += bytesRecv;

#ifdef VERBOSE
		cout << "HTTP Server: Received: "; 
		printAddressPort(i_Index); 
		cout << " " << bytesRecv << " bytes of \n ---START---\n" << &sockets[i_Index].buffer[len] << "\n ---END---\n";
#endif

		if(sockets[i_Index].len > 0)
		{
			if(HandleRequest(i_Index))
			{

				sockets[i_Index].send = SEND;
			}
		}
	}
}

void printCurrentSockets()
{
	int i;

	cout << "Printing current sockets state..." << endl;

	for(i = 0; i < socketCount; i++)
	{
		cout << i+1 << ":" << endl
			<< "id = " << sockets[i].id  << endl 
			<< " recv = " <<  sockets[i].recv << endl 
			<< " send = " <<  sockets[i].send << endl 
			<< " len = " <<  sockets[i].len << endl 
			<< " buffer = " <<  sockets[i].buffer << endl 
			<< " file size = " <<  sockets[i].fileSize << endl;
	}
}




